package org.Shiikong_Memory.SakuraBlockFrame.DataTool;

import com.google.gson.Gson;
import org.Shiikong_Memory.SakuraBlockFrame.Abnormal.NoInitAbnomal;
import org.bukkit.Bukkit;
import org.bukkit.NamespacedKey;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.entity.Entity;
import org.bukkit.inventory.ItemStack;
import org.bukkit.entity.Player;
import org.bukkit.entity.LivingEntity;
import org.bukkit.inventory.meta.ItemMeta;
import org.bukkit.metadata.FixedMetadataValue;
import org.bukkit.metadata.Metadatable;
import org.bukkit.persistence.PersistentDataContainer;
import org.bukkit.persistence.PersistentDataType;
import org.bukkit.plugin.Plugin;

import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;

/**
 * PersistenceTool 类提供了一套持久化数据保存和读取的工具方法，
 * 用于在 Bukkit 插件中操作物品栈（ItemStack）、生物（LivingEntity）和玩家（Player）的持久化数据容器（PersistentDataContainer）。
 * @author Shiikong_Memory
 * @version 1.0
 */
public class PersistenceTool {
    /**
     * 命名空间键，用于标识持久化数据的命名空间，在 init 方法中初始化。
     */
    private final Plugin plugin;
    /**
     * Gson 实例，用于将对象序列化为 JSON 字符串，以及将 JSON 字符串反序列化为对象。
     */
    private final Gson gson = new Gson();

    private final Map<String, NamespacedKey> keyCache = new ConcurrentHashMap<>();


    /**
     * 初始化工具，需在插件启动时调用。
     * 该方法会创建一个命名空间键，并将工具标记为已初始化。
     *
     * @param plugin 插件实例，用于创建命名空间键。
     */
    public PersistenceTool(Plugin plugin) {
        this.plugin = plugin;
    }
    /**
     * 通用保存方法，将数据保存到目标对象的持久化数据容器中。
     *
     * @param <T> 数据的类型。
     * @param target 目标对象，可以是 ItemStack、LivingEntity 或 Player。
     * @param dataKey 数据的键，用于在持久化数据容器中标识数据。
     * @param data 要保存的数据。
     * @throws NoInitAbnomal 如果工具未初始化，抛出此异常。
     */
    public <T> void saveData(Object target, String dataKey, T data) throws NoInitAbnomal{
        PersistentDataContainer pdc = getPdc(target);
        if (pdc != null) {
            // 复用命名空间创建新Key
            NamespacedKey compositeKey = keyCache.computeIfAbsent(dataKey,
                    k -> new NamespacedKey(plugin, k));
            pdc.set(compositeKey, PersistentDataType.STRING, gson.toJson(data));

            // 新增对ItemStack的特殊处理
            if (target instanceof ItemStack item) {
                item.setItemMeta(item.getItemMeta());
            }
        } else if (target instanceof Metadatable) {
            Metadatable metaTarget = (Metadatable) target;
            if (metaTarget.hasMetadata(dataKey)) {
                metaTarget.removeMetadata(dataKey, plugin);
            }
            metaTarget.setMetadata(dataKey, new FixedMetadataValue(plugin, gson.toJson(data)));
        }
    }

    /**
     * 通用读取方法，从目标对象的持久化数据容器中读取数据。
     *
     * @param <T> 数据的类型。
     * @param target 目标对象，可以是 ItemStack、LivingEntity 或 Player。
     * @param dataKey 数据的键，用于在持久化数据容器中查找数据。
     * @param type 数据的类类型，用于将 JSON 字符串反序列化为对应的对象。
     * @return 包含读取数据的 Optional 对象，如果未找到数据则返回空的 Optional。
     * @throws NoInitAbnomal 如果工具未初始化，抛出此异常。
     */
    public <T> Optional<T> readData(Object target, String dataKey, Class<T> type) throws NoInitAbnomal{
        PersistentDataContainer pdc = getPdc(target);
        if (pdc != null) {
            NamespacedKey compositeKey = keyCache.computeIfAbsent(dataKey,
                    k -> new NamespacedKey(plugin, k));
            String json = pdc.get(compositeKey, PersistentDataType.STRING);
            return Optional.ofNullable(gson.fromJson(json, type));
        }else if (target instanceof Metadatable metaTarget) {
            String string = metaTarget.getMetadata(dataKey).get(0).asString();
            return Optional.ofNullable(gson.fromJson(string, type));
        }
        return Optional.empty();
    }

    /**
     * 删除数据方法，从目标对象的持久化数据容器中删除指定键的数据。
     *
     * @param target 目标对象，可以是 ItemStack、LivingEntity 或 Player。
     * @param dataKey 数据的键，用于在持久化数据容器中查找并删除数据。
     * @throws NoInitAbnomal 如果工具未初始化，抛出此异常。
     */
    public void removeData(Object target, String dataKey) throws NoInitAbnomal{
        PersistentDataContainer pdc = getPdc(target);
        if (pdc != null) {
            NamespacedKey compositeKey = keyCache.get(dataKey);
            if (compositeKey != null) {
                pdc.remove(compositeKey);
            }
            if (target instanceof ItemStack item) {
                // 强制更新ItemMeta
                ItemMeta meta = item.getItemMeta();
                item.setItemMeta(meta);  // 重新设置使持久化数据生效
            }
        }else if (target instanceof Metadatable metaTarget) {
            metaTarget.removeMetadata(dataKey, plugin);
        }
    }

    /**
     * 私有方法，根据目标对象的类型获取其持久化数据容器。
     *
     * @param target 目标对象，可以是 ItemStack、LivingEntity 或 Player。
     * @return 目标对象的持久化数据容器，如果目标对象类型不支持则返回 null。
     * @throws NoInitAbnomal 如果工具未初始化，抛出此异常。
     */
    private PersistentDataContainer getPdc(Object target) throws NoInitAbnomal{
        if (target instanceof ItemStack item) {
            if (!item.hasItemMeta()) {
                ItemMeta meta = Bukkit.getItemFactory().getItemMeta(item.getType());
                item.setItemMeta(meta);
            }
            return item.getItemMeta().getPersistentDataContainer();
        } else if (target instanceof Entity entity) {
            return entity.getPersistentDataContainer();
        }
        return null;
    }
}